home *** CD-ROM | disk | FTP | other *** search
/ C# & Game Programming - A…er's Guide (2nd Edition) / Buono 2nd Ed.iso / Chapter3 / AsteroidMiner / AsteroidMiner Forms / AsteroidMinerGDI+.cs < prev    next >
Text File  |  2004-09-02  |  25KB  |  634 lines

  1. /* AsteroidMiner v2.0 - by Salvatore A. Buono */
  2. using System;
  3. using System.Drawing;
  4. using System.Windows.Forms;
  5. using System.IO; // for file read/write
  6.  
  7. using GameClasses; // Our common utility class
  8.  
  9. namespace Games {
  10.     public class AsteroidMiner : System.Windows.Forms.Form {
  11.         // Constants
  12.         const int SCALE = 25;
  13.         const string MEDIA_ROOT = @".\media\";
  14.         const int TIMER_BASE = 40;    // in millis.
  15.         const int MAX_STARS = 20;     // # of stars
  16.         const int MAX_ASTEROIDS = 4;  // # of asteroids (if on)
  17.         const int MAX_MISSILES = 2;   // # of missiles/ship
  18.         const int MISSILE_LIFE = 50;  // 40 ticks
  19.         const int THRUSTER_LIFE = 10; // 10 ticks
  20.         const int ASTEROID_SPEED = 10;// how much they move
  21.         const int GRAVITY_SPEED = 75; // how often gravity affects you
  22.         const int GRAVITY_EFFECT = 5; // how much it effects you
  23.         const int DEFAULT_SPEED = 5;  // default game speed
  24.         const int NUM_LIVES = 5;      // determines when the game is over
  25.         const int SCORE_ASTEROID = 10; // 10 points for hitting an asteroid
  26.  
  27.         // Image buffer to prevent screen-flicker
  28.         Bitmap offScreenBuffer;
  29.  
  30.         // Member fields -- UI elements
  31.         private System.Windows.Forms.MainMenu mainMenu1;
  32.         private System.Windows.Forms.MenuItem menuItem1;
  33.  
  34.         // Member fields
  35.         GameState gameState;  // Holds state information
  36.         PlayerImageArray player;
  37.  
  38.         AnimatedImage[] exhaustImages;
  39.         AnimatedImage[] playerMissiles;
  40.         AnimatedImage[] asteroids;
  41.  
  42.         Point[] stars;  // background star field
  43.         Image imgStar;
  44.  
  45.         GameTimer timer;    // Event timer to control all animation
  46.         TimedEvent p1Event; // The player event, for easy reference
  47.  
  48.         int HighScore = 0;
  49.         private System.Windows.Forms.MenuItem menuItem2;        // Game's top score loads from file
  50.         int p1LastDirection = 0;
  51.  
  52.         // Main entry-point function
  53.         [STAThread] static void Main() {
  54.             Application.Run(new AsteroidMiner());
  55.         }
  56.  
  57.     #region Set-up & Initialization
  58.         // Default constructor
  59.         public AsteroidMiner() {
  60.             InitializeComponent();
  61.  
  62.             gameState = new GameState();
  63.  
  64.             // Set up timer & timed events
  65.             timer = new GameTimer(TIMER_BASE);
  66.             TimedEvent newEvent;
  67.  
  68.             // Initialize the two player objects
  69.             player = new PlayerImageArray(9);
  70.             player.constraintBox = this.ClientRectangle;
  71.  
  72.             // Load images into PlayerImageArrays
  73.             player.LoadImage(MEDIA_ROOT + "FireBall.JPG", 0);
  74.             player.LoadImages(MEDIA_ROOT + "Ship1-%%.JPG", 1, 8);
  75.             player.RescaleImage(SCALE, SCALE);
  76.  
  77.             // player thruster event
  78.             newEvent = new TimedEvent(THRUSTER_LIFE, 
  79.                 new TickHandler(PlayerThrust));
  80.             newEvent.payload = player;
  81.             timer.addEvent(newEvent, 1, "player");
  82.             p1Event = newEvent;
  83.  
  84.             // Initialize exhaust images
  85.             exhaustImages = new AnimatedImage[9];
  86.             for (int i = 0; i < 9; i ++) {
  87.                 exhaustImages[i] = new AnimatedImage(0, 0);
  88.                 exhaustImages[i].imageData = Utils.LoadImage(MEDIA_ROOT + 
  89.                     "Exhaust" + i + ".JPG");
  90.                 exhaustImages[i].RescaleImage(SCALE / 2, SCALE / 2);
  91.             }
  92.             // Set correct image offsets
  93.             exhaustImages[1].imageOffsetX = 14;
  94.             exhaustImages[1].imageOffsetY = -5;
  95.             exhaustImages[2].imageOffsetX = 9;
  96.             exhaustImages[2].imageOffsetY = -9;
  97.             exhaustImages[3].imageOffsetX = 0;
  98.             exhaustImages[3].imageOffsetY = -6;
  99.             exhaustImages[4].imageOffsetX = -8;
  100.             exhaustImages[4].imageOffsetY = 6;
  101.             exhaustImages[5].imageOffsetX = 1;
  102.             exhaustImages[5].imageOffsetY = 17;
  103.             exhaustImages[6].imageOffsetX = 8;
  104.             exhaustImages[6].imageOffsetY = 20;
  105.             exhaustImages[7].imageOffsetX = 11;
  106.             exhaustImages[7].imageOffsetY = 17;
  107.             exhaustImages[8].imageOffsetX = 20;
  108.             exhaustImages[8].imageOffsetY = 6;
  109.  
  110.             // Initialize the background stars
  111.             Random rnd = new Random();
  112.             stars = new Point[MAX_STARS];
  113.             for (int i = 0; i < MAX_STARS; i++)
  114.                 stars[i] = new Point(rnd.Next(ClientSize.Width), rnd.Next(ClientSize.Height));
  115.  
  116.             imgStar = Utils.LoadImage(MEDIA_ROOT + "FireBall.JPG");
  117.  
  118.             // Initialize player's missiles
  119.             playerMissiles = new AnimatedImage[MAX_MISSILES];
  120.             for (int i = 0; i < MAX_MISSILES; i++) {
  121.                 playerMissiles[i] = new AnimatedImage(0, 0);
  122.                 playerMissiles[i].owner = player;
  123.                 playerMissiles[i].constraintBox = this.ClientRectangle;
  124.                 playerMissiles[i].imageData = Utils.LoadImage(MEDIA_ROOT + 
  125.                     "Weapon1.JPG");
  126.                 playerMissiles[i].RescaleImage(SCALE / 5, SCALE / 5);
  127.  
  128.                 // Set up timer & events
  129.                 newEvent = new TimedEvent(MISSILE_LIFE, 
  130.                     new TickHandler(MoveMissile));
  131.                 newEvent.payload = playerMissiles[i];
  132.                 timer.addEvent(newEvent, 1, "playerMissile" + i);
  133.             }
  134.  
  135.             // Initialize the asteroids
  136.             asteroids = new AnimatedImage[MAX_ASTEROIDS];
  137.             for (int i = 0; i < MAX_ASTEROIDS; i++) {
  138.                 // Note, there are only 4 image positions so strange
  139.                 // things happen when MAX_ASTEROIDS > 4
  140.                 asteroids[i] = new AnimatedImage((i % 2 == 1) ? 3 * SCALE :
  141.                     20 * SCALE, (i < 2 ? 3 * SCALE : 12 * SCALE));
  142.                 asteroids[i].direction = rnd.Next(1, 8);
  143.                 asteroids[i].constraintBox = this.ClientRectangle;
  144.                 asteroids[i].imageData = Utils.LoadImage(MEDIA_ROOT + 
  145.                     "Asteroid" + i + ".JPG");
  146.                 asteroids[i].RescaleImage(2 * SCALE, 2 * SCALE);
  147.  
  148.                 newEvent = new TimedEvent(new TickHandler(MoveAsteroids));
  149.                 newEvent.payload = asteroids[i];
  150.                 timer.addEvent(newEvent, ASTEROID_SPEED, "asteroid" + i);
  151.                 newEvent.isActive = true;
  152.             }
  153.  
  154.             newEvent = new TimedEvent(new TickHandler(Gravity));
  155.             newEvent.isActive = true;
  156.             timer.addEvent(newEvent, GRAVITY_SPEED, "");
  157.  
  158.             // Call Invalidate() every tick
  159.             newEvent = new TimedEvent(new TickHandler(ScreenRefresh));
  160.             timer.addEvent(newEvent, 1, "invalidate");
  161.             newEvent.isActive = true;
  162.  
  163.  
  164.       
  165.         }
  166.  
  167.         // (re) Sets positional data, scores, and other game data
  168.         public void Setup() {
  169.             gameState.currentState = GameState.State.Started;
  170.             gameState.currentSpeed = DEFAULT_SPEED;
  171.  
  172.             player.imagePosX = 12 * SCALE - (player.imageWidth >> 1);
  173.             player.imagePosY = 8 * SCALE;
  174.  
  175.             if (player.score > HighScore)
  176.                 SaveHighScore(player.score);
  177.             HighScore = LoadHighScore();
  178.             if(HighScore < player.score) {
  179.         HighScore = player.score;}
  180.             player.score = 0;
  181.  
  182.       
  183.             player.deaths = 0;
  184.             player.isActive = true;
  185.             player.direction = AnimatedImage.NORTH;
  186.  
  187.             for (int i = 0; i < MAX_MISSILES; i++) {
  188.                 playerMissiles[i].isActive = false;
  189.             }
  190.  
  191.             for (int i = 0; i < MAX_ASTEROIDS; i++) {
  192.                 asteroids[i].RescaleImage(2 * SCALE, 2 * SCALE);
  193.                 asteroids[i].isActive = true;
  194.             }
  195.  
  196.             timer.Start();
  197.         }
  198.  
  199.         // Form's initialize method - we initialize all form related items
  200.         private void InitializeComponent() {
  201.             this.mainMenu1 = new System.Windows.Forms.MainMenu();
  202.             this.menuItem1 = new System.Windows.Forms.MenuItem();
  203.             this.menuItem2 = new System.Windows.Forms.MenuItem();
  204.             // 
  205.             // mainMenu1
  206.             // 
  207.             this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
  208.                                                                                       this.menuItem1,
  209.                                                                                       this.menuItem2});
  210.             // 
  211.             // menuItem1
  212.             // 
  213.             this.menuItem1.Index = 0;
  214.             this.menuItem1.Text = "Asteroid Miner";
  215.             this.menuItem1.Click += new System.EventHandler(this.SinglePlayer_Click);
  216.             // 
  217.             // menuItem2
  218.             // 
  219.             this.menuItem2.Index = 1;
  220.             this.menuItem2.Text = "";
  221.             // 
  222.             // AsteroidMiner
  223.             // 
  224.             this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
  225.             this.BackColor = System.Drawing.Color.Black;
  226.             this.ClientSize = new System.Drawing.Size(600, 400);
  227.             this.Menu = this.mainMenu1;
  228.             this.Name = "AsteroidMiner";
  229.             this.Text = "Asteroid Miner";
  230.             this.Load += new System.EventHandler(this.AsteroidMiner_Load);
  231.  
  232.         }
  233.     #endregion
  234.  
  235.     #region Game-play functions
  236.         // Start up the player's thrusters
  237.         public void EngageThrusters(Player player) {
  238.             if (player.isActive) {
  239.                 if (player == player)
  240.                     p1Event.Reset(); // reset the timer from now
  241.  
  242.                 Utils.PlaySound(MEDIA_ROOT + "Thrust.wav");
  243.             }
  244.  
  245.             return;
  246.         }
  247.  
  248.         // Fire a missile (if any available) from the given player
  249.         public void FireMissile(Player player, AnimatedImage[] missiles) {
  250.             if (!player.isActive)
  251.                 return;
  252.  
  253.             for (int i = 0; i < MAX_MISSILES; i++) {
  254.                 // shoot the first missile that's not already out there!
  255.                 if (!missiles[i].isActive) {
  256.                     // set missiles properties so that it will get 
  257.                     // properly animated
  258.                     missiles[i].isActive = true;
  259.                     missiles[i].direction = player.direction;
  260.                     missiles[i].imagePosX = player.imagePosX;
  261.                     missiles[i].imagePosY = player.imagePosY;
  262.  
  263.                     TimedEvent missileEvent = timer.getEvent
  264.                         ("playerMissile" + i);
  265.                     missileEvent.Reset();
  266.  
  267.                     Utils.PlaySound(MEDIA_ROOT + "Fire.wav");
  268.                     break;
  269.                 }
  270.             }
  271.         }
  272.  
  273.         public void ExertGravitationalPull(Player player) {
  274.             if (player.imagePosX != ClientSize.Width >> 1)
  275.                 player.imagePosX += (player.imagePosX > 
  276.                     (ClientSize.Width >> 1)) ? -GRAVITY_EFFECT : GRAVITY_EFFECT;
  277.             if (player.imagePosY != ClientSize.Height >> 1)
  278.                 player.imagePosY += (player.imagePosY > 
  279.                     (ClientSize.Height >> 1)) ? -GRAVITY_EFFECT : GRAVITY_EFFECT;
  280.         }
  281.     #endregion
  282.  
  283.     #region Collision Detection Routines
  284.         // Ships can run into the asteroids and missiles.
  285.         // We'll assume that the missiles will detect their collisions
  286.         // so we only have to worry about the others.
  287.         public bool CheckShipCollision(Player player) {      
  288.             Player opponent = player;
  289.  
  290.             // Asteroid collision?
  291.             for (int i = 0; i < MAX_ASTEROIDS; i++) {
  292.                 if (asteroids[i].isActive) {
  293.                     if (asteroids[i].Intersects(player)) {
  294.                         ShipCollided(player);
  295.                         return true;
  296.                     }
  297.                 }
  298.             }
  299.  
  300.             return false;
  301.         }
  302.  
  303.         // Asteroids can run into ships & missiles. We'll assume that 
  304.         // missiles will detect their collisions themselves since they 
  305.         // update frequently.
  306.         public bool CheckAsteroidCollision() {
  307.             for (int i = 0; i < MAX_ASTEROIDS; i++) {
  308.                 if (asteroids[i].isActive) {
  309.                     if (asteroids[i].Intersects(player)) {
  310.                         ShipCollided(player);
  311.                         return true;
  312.                     }
  313.                 }
  314.             }
  315.  
  316.             return false;
  317.         }
  318.  
  319.         // Missiles can only run into asteroids.
  320.         public bool CheckMissileCollision(AnimatedImage missile) {
  321.             if (missile.isActive) {
  322.                 for (int i = 0; i < MAX_ASTEROIDS; i++) {
  323.                     if (missile.Intersects(asteroids[i])) {
  324.                         AsteroidCollided(asteroids[i]);
  325.                         missile.isActive = false;
  326.                         Utils.PlaySound(MEDIA_ROOT + "Hit.wav");
  327.                         return true;
  328.                     }
  329.                 }
  330.             }
  331.  
  332.             return false;  // Must not have hit anything!
  333.         }
  334.  
  335.         // The ship ran into something! Add to the death count and
  336.         // end the game if we're out of lives.
  337.         public void ShipCollided(Player victim) {
  338.             if (!victim.isActive)
  339.                 return; // He's already dead!
  340.  
  341.             victim.isActive = false;
  342.             victim.direction = 0; // index of our explosion image
  343.             Utils.PlaySound(MEDIA_ROOT + "Hit.wav");
  344.  
  345.             victim.deaths++;
  346.  
  347.             if(victim.deaths >= NUM_LIVES) {
  348.                 gameState.currentState = GameState.State.Stopped;
  349.  
  350.                 if (victim.score > HighScore) {
  351.                     SaveHighScore(victim.score);
  352.                 }
  353.             }
  354.         }
  355.  
  356.         // The asteroid was hit! Cycle through its different scaled
  357.         // display & increment the player's score.
  358.         public void AsteroidCollided(AnimatedImage victim) {
  359.             int scaleFactor = (victim.imageWidth <= (SCALE / 2)) ? 
  360.                 SCALE * 2 : victim.imageWidth / 2;
  361.             victim.RescaleImage(scaleFactor, scaleFactor);
  362.  
  363.             player.score += SCORE_ASTEROID;
  364.         }
  365.     #endregion
  366.  
  367.     #region OnPaint
  368.         protected override void OnPaint(PaintEventArgs e) {
  369.             Graphics gOffScreen;     // Graphics context for offscreen buffer
  370.             Graphics g = e.Graphics; // Screen's graphics object
  371.  
  372.             // If the size of the window has changed, we need a new buffer
  373.             if (offScreenBuffer == null || 
  374.                 offScreenBuffer.Width != this.ClientSize.Width ||
  375.                 offScreenBuffer.Height != this.ClientSize.Height) {
  376.                 if (ClientSize.Width == 0 || ClientSize.Height == 0)
  377.                     return;
  378.                 offScreenBuffer = new Bitmap(this.ClientSize.Width,
  379.                     this.ClientSize.Height);
  380.             }
  381.  
  382.             // We paint just as if it were the screen. The function need not
  383.             // know it is being buffered.
  384.             gOffScreen = Graphics.FromImage(offScreenBuffer);
  385.             DoPaint(gOffScreen);   // Call normal paint method
  386.             gOffScreen.Dispose();  // Free up resources right away
  387.  
  388.             // We draw our buffered image onto the screen in one operation.
  389.             // This could be improved further still by using clip regions.
  390.             g.DrawImage(offScreenBuffer, 0, 0);
  391.         }
  392.  
  393.         public void DoPaint(Graphics g) {
  394.             // Redraw the background
  395.             g.FillRectangle(Brushes.Black, 0, 0,
  396.                 this.Size.Width, this.Size.Height);
  397.  
  398.             // Write start-up text if game is stopped
  399.             if (gameState.currentState == GameState.State.Stopped) {
  400.                 Brush YellowBrush = Brushes.Yellow;
  401.                 Font LargeAlgerianFont = new Font("Algerian", 24);
  402.                 Font MidAlgerianFont = new Font("Algerian", 18);
  403.  
  404.                 g.DrawString("C# and Game Programming", LargeAlgerianFont, YellowBrush, 2 * SCALE, SCALE);
  405.                 g.DrawString("A Beginner's Guide", LargeAlgerianFont, YellowBrush, 9 * SCALE, 5 * SCALE);
  406.                 g.DrawString("By Salvatore A. Buono", MidAlgerianFont, YellowBrush, 2 * SCALE, 14 * SCALE);
  407.             }    else {
  408.                 // Draw the scores
  409.                 Font normal = new Font("Time New Roman", 14, FontStyle.Bold);
  410.                 if(player.score < HighScore) {
  411.           g.DrawString(HighScore.ToString(), normal, Brushes.Blue, 
  412.               4 * SCALE, SCALE);}
  413.                 else {
  414.                     g.DrawString(player.score.ToString(), normal,  Brushes.Blue, 
  415.                         4 * SCALE, SCALE);}
  416.                 g.DrawString(player.score.ToString(), normal,  Brushes.Blue, 
  417.                     16 * SCALE, SCALE);
  418.  
  419.                 // Draw the stars
  420.                 for(int i = 0; i < MAX_STARS; i++)
  421.                     g.DrawImage(imgStar, stars[i].X, stars[i].Y, 10, 10);
  422.  
  423.                 // Draw player 1 & its appropriate exhaust
  424.                 player.Display(g);
  425.                 if (p1Event.isActive) {
  426.                     exhaustImages[player.direction].imagePosX = player.imagePosX;
  427.                     exhaustImages[player.direction].imagePosY = player.imagePosY;
  428.                     exhaustImages[player.direction].Display(g);
  429.                 }
  430.  
  431.                 // Draw missiles
  432.                 for (int i = 0; i < MAX_MISSILES; i ++) {
  433.                     if (playerMissiles[i].isActive)
  434.                         playerMissiles[i].Display(g);
  435.                 }
  436.  
  437.                 // Draw asteroids
  438.                 for (int i = 0; i < MAX_ASTEROIDS; i++) {
  439.                     asteroids[i].Display(g);
  440.                 }
  441.             }
  442.         }
  443.     #endregion
  444.  
  445.     #region OnKey
  446.         protected override void OnKeyDown(KeyEventArgs e) {
  447.             if (gameState.currentState != GameState.State.Started) 
  448.                 return;
  449.  
  450.             // Player controls
  451.             switch(e.KeyCode) {
  452.                 case Keys.Up:
  453.                     p1LastDirection = player.direction;
  454.                     EngageThrusters(player);
  455.                     break;
  456.                 case Keys.Left:
  457.                     if (player.isActive)
  458.                         player.RotateDirection(1);
  459.                     break;
  460.                 case Keys.Right:
  461.                     if (player.isActive)
  462.                         player.RotateDirection(-1);
  463.                     break;
  464.                 case Keys.Down:
  465.                     if (!player.isActive)
  466.                         player.isActive = true;
  467.                     player.RandomizePosition();
  468.                     break;
  469.                 case Keys.NumPad0:
  470.                 case Keys.Space:
  471.                     FireMissile(player, playerMissiles);
  472.                     break;
  473.  
  474.                     // Exit game
  475.                 case Keys.Escape:
  476.                     ExitApplication();
  477.                     break;
  478.             }
  479.             base.OnKeyDown(e);
  480.         }
  481.     #endregion    
  482.  
  483.     #region TimedEvent Tick Handlers
  484.         // Implements the player's thruster push. Called repetitively until
  485.         // the timer counts down to 0.
  486.         public void PlayerThrust(TimedEvent e, Object obj) {
  487.             if (gameState.currentState == GameState.State.Stopped) {
  488.                 e.isActive = false;
  489.                 return;
  490.             }
  491.  
  492.             Player player = (Player) obj;
  493.             int tempDir = player.direction;
  494.  
  495.             player.direction = p1LastDirection;
  496.             player.Animate();
  497.             player.Animate();
  498.             player.direction = tempDir;
  499.             player.WrapInBox();
  500.  
  501.             CheckShipCollision(player);
  502.         }
  503.  
  504.         // Implements the missile's movement. Called automatically until
  505.         // the timer counts down to 0.
  506.         public void MoveMissile(TimedEvent e, Object obj) {
  507.             if (gameState.currentState == GameState.State.Stopped) {
  508.                 e.isActive = false;
  509.                 return;
  510.             }
  511.  
  512.             // Get a proper missile object from the event
  513.             AnimatedImage missile = (AnimatedImage) obj;
  514.             for(int i = 0; i < gameState.currentSpeed; i++) {
  515.                 missile.Animate();
  516.                 missile.WrapInBox();
  517.  
  518.                 // See if we hit anything!
  519.                 CheckMissileCollision(missile);
  520.             }
  521.  
  522.             // disable the missile so it can be fired again
  523.             if (e.tickCounter <= 1)
  524.                 missile.isActive = false;
  525.         }
  526.  
  527.         // Implements the asteroid's random movement. This is called
  528.         // continously throughout the game.
  529.         public void MoveAsteroids(TimedEvent e, Object obj) {
  530.             if (gameState.currentState == GameState.State.Stopped) {
  531.                 e.isActive = false;
  532.                 return;
  533.             }
  534.  
  535.             Random rnd = new Random();
  536.             for(int i = 0; i < MAX_ASTEROIDS; i++) {
  537.                 if (rnd.Next(10) > 7) // Change the direction ~70% of the time
  538.                     asteroids[i].direction = rnd.Next(1, 8);
  539.                 asteroids[i].Animate();
  540.                 asteroids[i].WrapInBox();
  541.                 CheckAsteroidCollision();
  542.             }
  543.         }
  544.  
  545.         // Implements the gravity (from an unseen field -- that only 
  546.         // affects ships -- located at the center of the screen).
  547.         public void Gravity(TimedEvent e, Object obj) {
  548.             if (gameState.currentState == GameState.State.Stopped) {
  549.                 e.isActive = false;
  550.                 return;
  551.             }
  552.  
  553.             if (player.isActive){ // Doesn't pull "dead" ships
  554.                 ExertGravitationalPull(player);
  555.                 CheckShipCollision(player);
  556.             }
  557.  
  558.             Utils.PlaySound(MEDIA_ROOT + "Gravity.wav");
  559.         }
  560.  
  561.         // Regular refresh function. The screen will redraw every tick.
  562.         public void ScreenRefresh(TimedEvent e, Object obj) {Invalidate();}
  563.     #endregion
  564.  
  565.     #region Menu Click Handler
  566.         private void SinglePlayer_Click(object sender, System.EventArgs e) {
  567.             gameState.currentMode = GameState.Mode.SinglePlayer;
  568.             Setup();
  569.         }
  570.     #endregion
  571.  
  572.     #region File Read/Write
  573.         // Utility function to read the high score from a file
  574.         public int LoadHighScore() {
  575.             StreamReader file;
  576.             string strTemp = "";
  577.             int score = 0;
  578.  
  579.             try {
  580.                 file = new StreamReader(@".\HighScore.txt");
  581.                 for (int i = 0; i < 4; i++)
  582.                     strTemp = file.ReadLine();
  583.                 score = int.Parse(strTemp.Substring(0, strTemp.IndexOf("\t")));
  584.                 file.Close();
  585.             } catch (Exception e) {Console.WriteLine(e);}
  586.  
  587.             return score;
  588.         }
  589.  
  590.         // Utility function to write the high score from a file
  591.         public void SaveHighScore(int score) {
  592.             StreamWriter file;
  593.  
  594.             try {
  595.                 file = new StreamWriter(@".\HighScore.txt");
  596.                 file.WriteLine("Asteroid Miner High Scores");
  597.                 file.WriteLine("--------------------------");
  598.                 file.WriteLine();
  599.                 file.WriteLine(score + "\t" + DateTime.Now);
  600.                 file.Flush();
  601.                 file.Close();
  602.             } catch (Exception e) {Console.WriteLine(e);}
  603.         }
  604.     #endregion
  605.  
  606.         // Clean exit function
  607.         public void ExitApplication() {
  608.             if (MessageBox.Show ("Are you sure you want to quit?", "End Game", 
  609.                 MessageBoxButtons.YesNo) == DialogResult.Yes) 
  610.                 Application.Exit(); 
  611.         }
  612.  
  613.         // The default Invalidate clears the entire screen creating a very 
  614.         // undesireable flicker. This override allows the paint method to
  615.         // control it's redraw.
  616.         public new void Invalidate() {
  617.             OnPaint(new PaintEventArgs(Graphics.FromHwnd(this.Handle), 
  618.                 new Rectangle(new Point(0, 0), this.Size)));
  619.         }
  620.  
  621.         // The system occasionally also calls OnPaintBackground which will
  622.         // mean the screen will be cleared, painted with the background 
  623.         // color, then repainted. This is another cause of flicker, so we
  624.         // just override it and tell it not to do anything!
  625.         protected override void OnPaintBackground(PaintEventArgs e) {
  626.             // Do nothing!
  627.         }
  628.  
  629.         private void AsteroidMiner_Load(object sender, System.EventArgs e) {
  630.             
  631.         }
  632.     }
  633. }
  634.